using Engine.Graphics;
using SharpDX;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace Scenario_Editor.Controls
{
    /// <summary>
    /// A Control where you can edit WR2-Material properties.
    /// </summary>
    public partial class MaterialPainter : UserControl
    {
        #region Private Fields

        private Engine.Engine engine;
        private MaterialManager materialManager;
        private PaintMode paintMode;
        private Bitmap texture1;
        private Bitmap texture2;
        private Bitmap texture3;
        private int textureID1;
        private int textureID2;
        private int textureID3;
        private System.Drawing.Color vertexColor;

        #endregion Private Fields

        #region Public Constructors

        public MaterialPainter()
        {
            InitializeComponent();
            CurrentMappingMode = EnumMappingMode.material00;
            this.vertexColor = System.Drawing.Color.Black;

            //Sets the standard Vertex Color for a WR2 Scenario
            this.colorDialog.CustomColors = new int[]{
                System.Drawing.Color.FromArgb(0,0,0,0).ToArgb(),
                System.Drawing.Color.FromArgb(0,128,0,0).ToArgb(),
                System.Drawing.Color.FromArgb(0,255,0,0).ToArgb(),
                System.Drawing.Color.FromArgb(0,255,128,128).ToArgb(),
                System.Drawing.Color.FromArgb(0,0,128,128).ToArgb(),
                System.Drawing.Color.FromArgb(0,0,255,255).ToArgb(),
                System.Drawing.Color.FromArgb(0,128,255,255).ToArgb(),
                System.Drawing.Color.FromArgb(0,255,255,255).ToArgb(),
                System.Drawing.Color.FromArgb(0,0,0,255).ToArgb(),
            };
        }

        #endregion Public Constructors

        #region Public Enums

        [Flags]
        public enum PaintMode
        {
            Nothing = 0,
            PaintMaterial = 1,
            PaintVertexColor = 2,
            SmoothVertexColor = 4,
            LightenVertexColor = 8,
            DarkenVertexColor = 16
        }

        #endregion Public Enums

        #region Public Properties

        public EnumMappingMode CurrentMappingMode
        {
            get;
            set;
        }

        public MaterialManager MaterialManager
        {
            get { return materialManager; }
            set { materialManager = value; }
        }

        public PaintMode PaintMode1
        {
            get { return paintMode; }
        }

        public bool ShowDarkenVertexColorButton
        {
            get
            {
                return this.checkBox_DarkenVertexColor.Visible;
            }
            set
            {
                this.checkBox_DarkenVertexColor.Visible = value;
            }
        }

        public bool ShowLightenVertexColorButton
        {
            get
            {
                return this.checkBox_LightenVertexColor.Visible;
            }
            set
            {
                this.checkBox_LightenVertexColor.Visible = value;
            }
        }

        public bool ShowSmoothButton
        {
            get
            {
                return this.checkBox_SmoothVertexColor.Visible;
            }
            set
            {
                this.checkBox_SmoothVertexColor.Visible = value;
            }
        }

        public Color4 VertexColor
        {
            get
            {
                Color4 color = new Color4(
                    this.panel_CurrentVertexColor.BackColor.R / 255.0f,// Red
                    this.panel_CurrentVertexColor.BackColor.G / 255.0f,// Green
                    this.panel_CurrentVertexColor.BackColor.B / 255.0f,// Blue
                    0 // Alpha
                    );

                return color;
            }
        }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Gets the current adjusted Material
        /// </summary>
        /// <returns></returns>
        public Material GetMaterial()
        {
            LoadTexture(textureID1);
            LoadTexture(textureID2);
            LoadTexture(textureID3);
            return new Material(textureID1, textureID2, textureID3,
                CurrentMappingMode, MaterialManager,
                this.materialMappingsMatrix1.Mapping,
                this.materialMappingsMatrix2.Mapping,
                this.materialMappingsMatrix3.Mapping);
        }

        public void SaveCurrentMaterialToXML(string filename)
        {
            Material material = GetMaterial();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.Unicode;
            settings.Indent = true;
            settings.OmitXmlDeclaration = true;
            settings.NewLineOnAttributes = true;

            using (XmlWriter xmlWriter = XmlWriter.Create(filename, settings))
            {
                material.ToXmlStream(xmlWriter);
            }
        }

        public void SetDevice(MaterialManager materialManager)
        {
            this.MaterialManager = materialManager;
            if (this.materialManager.GetNumberOfMaterials() > 0)
                SetMaterial(this.materialManager.GetMaterial(0), null);
            this.engine = materialManager.Engine;
        }

        /// <summary>
        /// Set all controls to the sended material
        /// </summary>
        /// <param name="sender">the Material which send by event.</param>
        /// <param name="e">not used at the moment.</param>
        public void SetMaterial(object sender, EventArgs e)
        {
            Material material = (Material)sender;
            this.materialMappingsMatrix1.Mapping = material.Mappings1;
            this.materialMappingsMatrix2.Mapping = material.Mappings2;
            this.materialMappingsMatrix3.Mapping = material.Mappings3;
            this.textureID1 = this.MaterialManager.GetTextureID(material.TextureName1);
            this.textureID2 = this.MaterialManager.GetTextureID(material.TextureName2);
            this.textureID3 = this.MaterialManager.GetTextureID(material.TextureName3);

            LoadTexture(this.textureID1);
            LoadTexture(this.textureID2);
            LoadTexture(this.textureID3);

            UpdateTextureImage();
        }

        public void SetTexture(int textureID)
        {
            if (textureID > MaterialManager.TextureNames.Count)
            {
                Debug.WriteLine("textureID is bigger than the number of textures are avaible");
                textureID = 1;
            }

            if (this.tab_MappingsTextures.SelectedIndex == 0)
            {
                this.textureID1 = textureID;
            }
            if (this.tab_MappingsTextures.SelectedIndex == 1)
            {
                this.textureID2 = textureID;
                SetNewTexture(ref this.texture2, textureID2);
            }
            if (this.tab_MappingsTextures.SelectedIndex == 2)
            {
                this.textureID3 = textureID;
                SetNewTexture(ref this.texture3, textureID3);
            }
            UpdateTextureImage();
        }

        #endregion Public Methods

        #region Private Methods

        private void button_VertexColorDecrease_Click(object sender, EventArgs e)
        {
            System.Drawing.Color color = this.panel_CurrentVertexColor.BackColor;
            Vector3 newColor = new Vector3(color.R, color.G, color.B);
            newColor = Vector3.Multiply(newColor, 0.97f);
            int r = (int)newColor.X;
            int g = (int)newColor.Y;
            int b = (int)newColor.Z;
            if (r > 255) r = 255;
            if (g > 255) g = 255;
            if (b > 255) b = 255;
            color = System.Drawing.Color.FromArgb(255, r, g, b);
            this.panel_CurrentVertexColor.BackColor = color;
        }

        private void button_VertexColorIncrease_Click(object sender, EventArgs e)
        {
            System.Drawing.Color color = this.panel_CurrentVertexColor.BackColor;
            Vector3 newColor = new Vector3(color.R, color.G, color.B);
            newColor = Vector3.Multiply(newColor, 1.03f);
            int r = (int)newColor.X;
            int g = (int)newColor.Y;
            int b = (int)newColor.Z;
            if (r > 255) r = 255;
            if (g > 255) g = 255;
            if (b > 255) b = 255;
            color = System.Drawing.Color.FromArgb(255, r, g, b);
            this.panel_CurrentVertexColor.BackColor = color;
        }

        private void LoadTexture(int textureID)
        {
            if (MaterialManager.Textures.Length > 0)
            {
                if (MaterialManager.Textures[(int)textureID] == null)
                {
                    MaterialManager.Textures[(int)textureID] = Ptx2bmpConverter.Ptx2bmp.ToDDSSlimDX(this.engine.Device, MaterialManager.TexturePaths[(int)textureID]);
                }
            }
            else
            {
                MessageBox.Show("There are no Textures in your Texture-folder!!");
                Application.Exit();
                Application.DoEvents();
            }
        }

        private void OnPaintModeChanged(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(CheckBox))
            {
                ((CheckBox)sender).BackColor = (((CheckBox)sender).Checked) ? SystemColors.Highlight : SystemColors.Control;
            }

            this.paintMode = PaintMode.Nothing;

            if (this.checkBox_DarkenVertexColor.Checked | this.checkBox_LightenVertexColor.Checked)
            {
                this.checkBox_Material.Checked = false;
                this.checkBox_PaintVertexColor.Checked = false;

                if (this.checkBox_DarkenVertexColor.Checked)
                {
                    //this.checkBox_LightenVertexColor.Checked = false;
                    this.paintMode = PaintMode.DarkenVertexColor;
                }
                else if (this.checkBox_LightenVertexColor.Checked)
                {
                    //this.checkBox_DarkenVertexColor.Checked = false;
                    this.paintMode = PaintMode.LightenVertexColor;
                }
            }

            if (this.checkBox_Material.Checked)
                this.paintMode |= PaintMode.PaintMaterial;
            if (this.checkBox_PaintVertexColor.Checked)
                this.paintMode |= PaintMode.PaintVertexColor;
            if (this.checkBox_SmoothVertexColor.Checked)
                this.paintMode |= PaintMode.SmoothVertexColor;
        }

        private void panel1_MouseClick(object sender, MouseEventArgs e)
        {
            this.panel_CurrentVertexColor.BackColor = ((Panel)sender).BackColor;
        }

        private void panel1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Panel panel = (Panel)sender;
            this.colorDialog.Color = panel.BackColor;

            if (DialogResult.OK == this.colorDialog.ShowDialog())
            {
                panel.BackColor = this.colorDialog.Color;
            }
        }

        private void SetNewTexture(ref Bitmap texture, int textureID)
        {
            if (texture != null)
                texture.Dispose();

            string fileName = MaterialManager.TexturePaths[textureID];
            try
            {
                texture = Ptx2bmpConverter.Ptx2bmp.FromFile(fileName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error in Loading PTX-Texutre: " + fileName);
            }
        }

        private void tab_MappingsTextures_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateTextureImage();
        }

        private void UpdateTextureImage()
        {
            Bitmap image;//= new Bitmap(10, 10);
            Ptx2bmpConverter.Ptx2bmp.PtxType typeOfPTX = Ptx2bmpConverter.Ptx2bmp.PtxType.uncompressed32Bit;
            string texturePath = string.Empty;
            if (this.tab_MappingsTextures.SelectedIndex == 0)
            {
                texturePath = MaterialManager.TexturePaths[textureID1];
            }
            if (this.tab_MappingsTextures.SelectedIndex == 1)
            {
                texturePath = MaterialManager.TexturePaths[textureID2];
            }
            if (this.tab_MappingsTextures.SelectedIndex == 2)
            {
                texturePath = MaterialManager.TexturePaths[textureID3];
            }

            try
            {
                image = Ptx2bmpConverter.Ptx2bmp.FromFile(texturePath, out typeOfPTX);

                // Update the Preview Panel
                if (image.Size.Width > this.pictureBox1.ClientSize.Width)
                {
                    this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
                }
                else
                {
                    this.pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
                }

                if (this.pictureBox1.Image != null)
                    this.pictureBox1.Image.Dispose();

                this.pictureBox1.Image = image;

                //Update the Infos
                this.label_SizeX.Text = image.Size.Width.ToString();
                this.label_SizeY.Text = image.Size.Height.ToString();
                this.label_ptxType.Text = "( " + Path.GetFileNameWithoutExtension(texturePath) + " )  " + typeOfPTX.ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion Private Methods
    }
}